package com.ndkj.rpcserver.proxy.chain;

import com.ndkj.rpcserver.common.dto.Invocation;
import com.ndkj.rpcserver.common.dto.URL;
import com.ndkj.rpcserver.common.utils.HttpClient;
import com.ndkj.rpcserver.loadbalance.LoadBalanceRule;
import com.ndkj.rpcserver.register.MapRemoteRegister;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;

public class RpcInvocationChain implements Handler {

    @Override
    public boolean canHandle() {
        // 兜底处理，一律放行
        return true;
    }

    @Override
    public Object process(Class interfaceClazz, String version, Object proxy, Method method, Object[] args) throws IOException {
        // 代理信息
        Class<?>[] parameterTypes = method.getParameterTypes();
        Invocation invocationDTO = new Invocation(interfaceClazz.getName(), method.getName(), version, parameterTypes, args);

        // 服务发现
        List<URL> providerHosts = MapRemoteRegister.get(interfaceClazz.getName(), version);

        // 定义最大重试次数
        int tryTimes = 3;
        // 负载均衡后被选中的provider
        URL provider = null;

        for (int i = 0; i < tryTimes; i++) {
            try {
                // TODO: 这里也可以设计重试机制
                if (providerHosts == null || providerHosts.size() == 0) {
                    throw new RuntimeException("No service provider found");
                }
                // 负载均衡
                provider = LoadBalanceRule.randomRule(providerHosts);
                // 服务调用
                // 发送调用请求至目标机器，由目标机器上的LocalRegister本地缓存上注册的接口实现类执行（目标机器上进行泛化调用）
                HttpClient httpClient = new HttpClient();
                return httpClient.send(provider.getHost(), provider.getPort(), invocationDTO);
            } catch (Exception e) {
                providerHosts.remove(provider);
                if (--tryTimes > 0) {
                    continue;
                }
                throw e;
            }
        }
        return "Service invocation exception";
    }

}
